//
// Created by tcj on 2022/7/15.
//

#ifndef WEB_TEST_THREADPOOL_H
#define WEB_TEST_THREADPOOL_H

#include <thread>
#include "vector"
#include "condition_variable"
#include "mutex"
#include "queue"
#include "functional"
#include "future"
#include "iostream"


namespace tcj{
    class ThreadPool{
    public:
        explicit ThreadPool(size_t threadNumber):m_stop_(false){
            for(size_t i=0;i<threadNumber;++i){
                m_thread_.emplace_back([this](){
                    for(;;){
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lk(m_mutex_);
                            m_cv_.wait(lk,[this](){return m_stop_ || !tasks_.empty();});
                            if(m_stop_ && tasks_.empty()) return;
                            task = std::move(tasks_.front());
                            tasks_.pop();
                        }
                        task();
                    }
                });
                std::cout<<i<<" thread running "<<std::endl;
            }
        }

        ThreadPool(const ThreadPool &) = delete;
        ThreadPool(ThreadPool &&) = delete;

        ThreadPool &operator=(const ThreadPool &) = delete;
        ThreadPool &operator=(ThreadPool &)= delete;

        ~ThreadPool(){
            {
                std::unique_lock<std::mutex> lk(m_mutex_);
                m_stop_ = true;
            }
            m_cv_.notify_all();
            for(auto& threads : m_thread_){
                threads.join();
            }
        }


        /*。std::future提供了一种用于访问异步操作结果的机制。
         * std::future所引用的共享状态不能与任何其它异步返回的对象共享
         * */
        template<typename F,typename... Args>
        auto submit(F&& f,Args&& ...args)->std::future<decltype(f(args...))>{
            auto taskPtr = std::make_shared<std::packaged_task<decltype(f(args...))()>>(
                    std::bind(std::forward<F>(f),std::forward<Args>(args)...)
                );
            {
                std::unique_lock<std::mutex> lk(m_mutex_);
                if(m_stop_) throw std::runtime_error("error on stoppeed threadpool");
                tasks_.emplace([taskPtr](){ (*taskPtr)(); });
            }
            m_cv_.notify_one();
            return taskPtr->get_future();
        }


//        template<typename F,typename... Args>
//        auto submit(F&& f,Args&&... args)->std::future<decltype(f(args...))>{
//            auto taskPtr=std::make_shared<std::packaged_task<decltype(f(args...))()>>(
//                    std::bind(std::forward<F>(f),std::forward<Args>(args)...)
//            );
//            {
//                std::unique_lock<std::mutex>lk(m_mutex_);
//                if(m_stop_) throw std::runtime_error("submit on stopped ThreadPool");
//                tasks_.emplace([taskPtr](){ (*taskPtr)(); });
//            }
//            m_cv_.notify_one();
//            return taskPtr->get_future();
//
//        }



    private:
        bool m_stop_;                               // 表示是否要停止使用线程池
        std::vector<std::thread> m_thread_;         // 线程池
        std::mutex m_mutex_;                        // 锁
        std::queue<std::function<void()>> tasks_;   // 任务队列
        std::condition_variable m_cv_;              // 条件变量

    };
}


#endif //WEB_TEST_THREADPOOL_H